package com.github.yelisheng.utils;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ReflectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.conditions.AbstractChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import lombok.extern.slf4j.Slf4j;
import com.github.yelisheng.annotation.MpQuery;
import com.github.yelisheng.constant.QueryStatic;
import com.github.yelisheng.constant.QueryType;
import org.apache.logging.log4j.util.Strings;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.stream.Collectors;

/**
 * MyBatis Plus 工具类
 *
 * @author 叶璃笙
 */
@Slf4j
public class MpUtil<T> extends AbstractChainWrapper<T, SFunction<T, ?>, LambdaQueryChainWrapper<T>, LambdaQueryWrapper<T>> {

    /**
     * 构建实体类selectLambda
     *
     * @param <T> 数据库实体类
     * @return 条件构造器
     */
    public static <T> LambdaQueryWrapper<T> selectEntityWrapper() {
        return new QueryWrapper<T>().lambda();
    }

    /**
     * 构建实体类updateLambda
     *
     * @param <T> 数据库实体类
     * @return 条件构造器
     */
    public static <T> LambdaUpdateWrapper<T> updateEntityWrapper() {
        return new UpdateWrapper<T>().lambda();
    }

    /**
     * 生成查询条件包装器
     *
     * @param o 实体对象
     * @return QueryWrapper
     */
    public static QueryWrapper<Object> generateWrapper(Object o) {
        QueryWrapper<Object> wrapper = new QueryWrapper<>();
        generateWrapper(o, wrapper);
        return wrapper;
    }

    /**
     * 将实体对象转换为查询条件
     *
     * @param o       实体对象
     * @param wrapper 查询包装器
     */
    public static void generateWrapper(Object o, QueryWrapper<Object> wrapper) {
        try {
            Field[] allFields = ReflectUtil.getFields(o.getClass());

            for (Field field : allFields) {
                field.setAccessible(true);
                // 过滤static和final属性
                if (Modifier.isStatic(field.getModifiers())) {
                    continue;
                }
                // 过滤非基本类型
                if (!isSimpleType(field.getType())) {
                    continue;
                }

                // 数据表字段
                String column = QueryStatic.DEFAULT_PREFIX + humpToLine2(field.getName());

                // 字段值
                Object value = field.get(o);

                // 处理有注解的字段
                if (field.isAnnotationPresent(MpQuery.class)) {
                    MpQuery annotation = field.getAnnotation(MpQuery.class);
                    QueryType queryType = QueryType.fromValue(annotation.type().getValue());

                    // 使用自定义表前缀和字段属性
                    column = annotation.prefix() + QueryStatic.POINT + humpToLine2(field.getName());

                    // 使用自定义字段
                    column = getField(column, annotation);

                    // 处理默认值
                    value = getDefaultValue(annotation, value);

                    // 处理排序和分组
                    processOrderAndGroup(wrapper, annotation);

                    // 特殊处理CONDITION类型
                    if (queryType == QueryType.CONDITION) {
                        if (StringUtils.isNotBlank(annotation.condition())) {
                            applyCondition(wrapper, annotation, value);
                        }
                    }
                    // 应用查询条件
                    else if (shouldApplyCondition(queryType, value, annotation)) {
                        queryType.apply(wrapper, column, value);
                    }
                }
                // 无注解的字段默认使用EQ查询
                else if (ObjectUtils.isNotEmpty(value)) {
                    wrapper.eq(column, value);
                }
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Failed to generate query wrapper", e);
        }
    }

    /**
     * 判断是否需要应用查询条件
     */
    private static boolean shouldApplyCondition(QueryType queryType, Object value, MpQuery annotation) {
        return queryType == QueryType.IS_NULL
                || queryType == QueryType.IS_NOT_NULL
                || queryType == QueryType.IS_EMPTY
                || queryType == QueryType.IS_NOT_EMPTY
                || ObjectUtils.isNotEmpty(value)
                || StringUtils.isNotBlank(annotation.defaultValue());
    }

    /**
     * 处理排序和分组
     */
    private static void processOrderAndGroup(QueryWrapper<Object> wrapper, MpQuery annotation) {
        // 处理排序
        if (StringUtils.isNotBlank(annotation.orderBy())) {
            Arrays.stream(annotation.orderBy().split(","))
                    .map(String::trim)
                    .filter(StrUtil::isNotBlank)
                    .forEach(order -> {
                        String[] parts = order.split(":");
                        if (parts.length == 2) {
                            if ("DESC".equalsIgnoreCase(parts[1])) {
                                wrapper.orderByDesc(parts[0]);
                            } else {
                                wrapper.orderByAsc(parts[0]);
                            }
                        } else {
                            wrapper.orderByAsc(order);
                        }
                    });
        }

        // 处理分组
        if (StringUtils.isNotBlank(annotation.groupBy())) {
            wrapper.groupBy(Arrays.stream(annotation.groupBy().split(","))
                    .map(String::trim)
                    .filter(StrUtil::isNotBlank)
                    .collect(Collectors.toList()));
        }
    }

    /**
     * 应用自定义条件
     */
    private static void applyCondition(QueryWrapper<Object> wrapper, MpQuery annotation, Object value) {
        String condition = annotation.condition();
        if (annotation.conditionParams().length > 0) {
            Object[] params = Arrays.stream(annotation.conditionParams())
                    .map(param -> param.replace("#{value}",
                            value != null ? value.toString() : ""))
                    .filter(StrUtil::isNotBlank)
                    .toArray();
            wrapper.apply(condition, params);
        } else {
            wrapper.apply(condition);
        }
    }

    /**
     * 获取字段名
     */
    private static String getField(String column, MpQuery annotation) {
        String fd = annotation.field();
        if (Strings.isNotBlank(fd)) {
            column = annotation.prefix() + QueryStatic.POINT + humpToLine2(fd);
        }
        return column;
    }

    /**
     * 获取默认值
     */
    private static Object getDefaultValue(MpQuery annotation, Object value) {
        if (Strings.isNotBlank(annotation.defaultValue())) {
            try {
                String defaultValue = annotation.defaultValue();
                if (value == null) {
                    return defaultValue;
                }
                if (value instanceof Number) {
                    return Double.parseDouble(defaultValue);
                } else if (value instanceof Boolean) {
                    return Boolean.parseBoolean(defaultValue);
                }
                return defaultValue;
            } catch (Exception e) {
                log.warn("Failed to parse default value: {}", e.getMessage());
            }
        }
        return value;
    }

    /**
     * 判断是否为简单类型
     */
    private static boolean isSimpleType(Class<?> type) {
        return type.isPrimitive() ||
                type == String.class ||
                Number.class.isAssignableFrom(type) ||
                type == Boolean.class;
    }

    /**
     * 驼峰转下划线
     */
    private static String humpToLine2(String str) {
        return str.replaceAll("([A-Z])", "_$1").toLowerCase();
    }
}